home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / edit / elv18src.zip / cmd2.c < prev    next >
C/C++ Source or Header  |  1994-01-02  |  18KB  |  991 lines

  1. /* cmd2.c */
  2.  
  3. /* Author:
  4.  *    Steve Kirkendall
  5.  *    14407 SW Teal Blvd. #C
  6.  *    Beaverton, OR 97005
  7.  *    kirkenda@cs.pdx.edu
  8.  */
  9.  
  10.  
  11. /* This file contains some of the commands - mostly ones that change text */
  12.  
  13. #ifdef AIX
  14. # define _XOPEN_SOURCE
  15. # include <sys/mode.h>
  16. # include <sys/stat.h>
  17. # undef _XOPEN_SOURCE
  18. #endif
  19. #include "config.h"
  20. #include "ctype.h"
  21. #include "vi.h"
  22. #include "regexp.h"
  23. #if TOS
  24. # include <stat.h>
  25. #else
  26. # if OSK
  27. #  include "osk.h"
  28. # else
  29. #  if AMIGA
  30. #   include "amistat.h"
  31. #  else
  32. #   include <sys/stat.h>
  33. #  endif
  34. # endif
  35. #endif
  36.  
  37.  
  38. /*ARGSUSED*/
  39. void cmd_substitute(frommark, tomark, cmd, bang, extra)
  40.     MARK    frommark;
  41.     MARK    tomark;
  42.     CMD    cmd;
  43.     int    bang;
  44.     char    *extra;    /* rest of the command line */
  45. {
  46.     char    *line;    /* a line from the file */
  47.     regexp    *re;    /* the compiled search expression */
  48.     char    *subst;    /* the substitution string */
  49.     char    *opt;    /* substitution options */
  50.     long    l;    /* a line number */
  51.     char    *s, *d;    /* used during subtitutions */
  52.     char    *conf;    /* used during confirmation */
  53.     long    chline;    /* # of lines changed */
  54.     long    chsub;    /* # of substitutions made */
  55.     static    optp;    /* boolean option: print when done? */
  56.     static    optg;    /* boolean option: substitute globally in line? */
  57.     static    optc;    /* boolean option: confirm before subst? */
  58. #ifndef CRUNCH
  59.     long    oldnlines;
  60. #endif
  61.  
  62.  
  63.     /* for now, assume this will fail */
  64.     rptlines = -1L;
  65.  
  66.     if (cmd == CMD_SUBAGAIN)
  67.     {
  68. #ifndef NO_MAGIC
  69.         if (*o_magic)
  70.             subst = "~";
  71.         else
  72. #endif
  73.         subst = "\\~";
  74.         re = regcomp("");
  75.  
  76.         /* if visual "&", then turn off the "p" and "c" options */
  77.         if (bang)
  78.         {
  79.             optp = optc = FALSE;
  80.         }
  81.     }
  82.     else /* CMD_SUBSTITUTE */
  83.     {
  84.         /* make sure we got a search pattern */
  85.         if (!*extra)
  86.         {
  87.             msg("Usage: s/regular expression/new text/");
  88.             return;
  89.         }
  90.  
  91.         /* parse & compile the search pattern */
  92.         subst = parseptrn(extra);
  93.         re = regcomp(extra + 1);
  94.     }
  95.  
  96.     /* abort if RE error -- error message already given by regcomp() */
  97.     if (!re)
  98.     {
  99.         return;
  100.     }
  101.  
  102.     if (cmd == CMD_SUBSTITUTE)
  103.     {
  104.         /* parse the substitution string & find the option string */
  105.         for (opt = subst; *opt && *opt != *extra; opt++)
  106.         {
  107.             if (*opt == '\\' && opt[1])
  108.             {
  109.                 opt++;
  110.             }
  111.         }
  112.         if (*opt)
  113.         {
  114.             *opt++ = '\0';
  115.         }
  116.  
  117.         /* analyse the option string */
  118.         if (!*o_edcompatible)
  119.         {
  120.             optp = optg = optc = FALSE;
  121.         }
  122.         while (*opt)
  123.         {
  124.             switch (*opt++)
  125.             {
  126.               case 'p':    optp = !optp;    break;
  127.               case 'g':    optg = !optg;    break;
  128.               case 'c':    optc = !optc;    break;
  129.               case ' ':
  130.               case '\t':            break;
  131.               default:
  132.                 msg("Subst options are p, c, and g -- not %c", opt[-1]);
  133.                 return;
  134.             }
  135.         }
  136.     }
  137.  
  138.     /* if "c" or "p" flag was given, and we're in visual mode, then NEWLINE */
  139.     if ((optc || optp) && mode == MODE_VI)
  140.     {
  141.         addch('\n');
  142.         exrefresh();
  143.     }
  144.  
  145.     ChangeText
  146.     {
  147.         /* reset the change counters */
  148.         chline = chsub = 0L;
  149.  
  150.         /* for each selected line */
  151.         for (l = markline(frommark); l <= markline(tomark); l++)
  152.         {
  153.             /* fetch the line */
  154.             line = fetchline(l);
  155.  
  156.             /* if it contains the search pattern... */
  157.             if (regexec(re, line, TRUE))
  158.             {
  159.                 /* increment the line change counter */
  160.                 chline++;
  161.  
  162.                 /* initialize the pointers */
  163.                 s = line;
  164.                 d = tmpblk.c;
  165.  
  166.                 /* do once or globally ... */
  167.                 do
  168.                 {
  169. #ifndef CRUNCH
  170.                     /* confirm, if necessary */
  171.                     if (optc)
  172.                     {
  173.                         for (conf = line; conf < re->startp[0]; conf++)
  174.                             addch(*conf);
  175.                         standout();
  176.                         for ( ; conf < re->endp[0]; conf++)
  177.                             addch(*conf);
  178.                         standend();
  179.                         for (; *conf; conf++)
  180.                             addch(*conf);
  181.                         addch('\n');
  182.                         exrefresh();
  183.                         if (getkey(0) != 'y')
  184.                         {
  185.                             /* copy accross the original chars */
  186.                             while (s < re->endp[0])
  187.                                 *d++ = *s++;
  188.  
  189.                             /* skip to next match on this line, if any */
  190.                             goto Continue;
  191.                         }
  192.                     }
  193. #endif /* not CRUNCH */
  194.  
  195.                     /* increment the substitution change counter */
  196.                     chsub++;
  197.  
  198.                     /* copy stuff from before the match */
  199.                     while (s < re->startp[0])
  200.                     {
  201.                         *d++ = *s++;
  202.                     }
  203.  
  204.                     /* substitute for the matched part */
  205.                     regsub(re, subst, d);
  206.                     s = re->endp[0];
  207.                     d += strlen(d);
  208.  
  209. Continue:
  210.                     /* if this regexp could conceivably match
  211.                      * a zero-length string, then require at
  212.                      * least 1 unmatched character between
  213.                      * matches.
  214.                      */
  215.                     if (re->minlen == 0)
  216.                     {
  217.                         if (!*s)
  218.                             break;
  219.                         *d++ = *s++;
  220.                     }
  221.  
  222.                 } while (optg && regexec(re, s, FALSE));
  223.  
  224.                 /* copy stuff from after the match */
  225.                 while (*d++ = *s++)    /* yes, ASSIGNMENT! */
  226.                 {
  227.                 }
  228.  
  229. #ifndef CRUNCH
  230.                 /* NOTE: since the substitution text is allowed to have ^Ms which are
  231.                  * translated into newlines, it is possible that the number of lines
  232.                  * in the file will increase after each line has been substituted.
  233.                  * we need to adjust for this.
  234.                  */
  235.                 oldnlines = nlines;
  236. #endif
  237.  
  238.                 /* replace the old version of the line with the new */
  239.                 d[-1] = '\n';
  240.                 d[0] = '\0';
  241.                 change(MARK_AT_LINE(l), MARK_AT_LINE(l + 1), tmpblk.c);
  242.  
  243. #ifndef CRUNCH
  244.                 l += nlines - oldnlines;
  245.                 tomark += MARK_AT_LINE(nlines - oldnlines);
  246. #endif
  247.  
  248.                 /* if supposed to print it, do so */
  249.                 if (optp)
  250.                 {
  251.                     addstr(tmpblk.c);
  252.                     exrefresh();
  253.                 }
  254.  
  255.                 /* move the cursor to that line */
  256.                 cursor = MARK_AT_LINE(l);
  257.             }
  258.         }
  259.     }
  260.  
  261.     /* free the regexp */
  262.     _free_(re);
  263.  
  264.     /* if done from within a ":g" command, then finish silently */
  265.     if (doingglobal)
  266.     {
  267.         rptlines = chline;
  268.         rptlabel = "changed";
  269.         return;
  270.     }
  271.  
  272.     /* Reporting */
  273.     if (chsub == 0)
  274.     {
  275.         msg("Substitution failed");
  276.     }
  277.     else if (chline >= *o_report)
  278.     {
  279.         msg("%ld substitutions on %ld lines", chsub, chline);
  280.     }
  281.     rptlines = 0L;
  282. }
  283.  
  284.  
  285.  
  286.  
  287. /*ARGSUSED*/
  288. void cmd_delete(frommark, tomark, cmd, bang, extra)
  289.     MARK    frommark;
  290.     MARK    tomark;
  291.     CMD    cmd;
  292.     int    bang;
  293.     char    *extra;
  294. {
  295.     MARK    curs2;    /* an altered form of the cursor */
  296.  
  297.     /* choose your cut buffer */
  298.     if (*extra == '"')
  299.     {
  300.         extra++;
  301.     }
  302.     if (*extra)
  303.     {
  304.         cutname(*extra);
  305.     }
  306.  
  307.     /* make sure we're talking about whole lines here */
  308.     frommark = frommark & ~(BLKSIZE - 1);
  309.     tomark = (tomark & ~(BLKSIZE - 1)) + BLKSIZE;
  310.  
  311.     /* yank the lines */
  312.     cut(frommark, tomark);
  313.  
  314.     /* if CMD_DELETE then delete the lines */
  315.     if (cmd != CMD_YANK)
  316.     {
  317.         curs2 = cursor;
  318.         ChangeText
  319.         {
  320.             /* delete the lines */
  321.             delete(frommark, tomark);
  322.         }
  323.         if (curs2 > tomark)
  324.         {
  325.             cursor = curs2 - tomark + frommark;
  326.         }
  327.         else if (curs2 > frommark)
  328.         {
  329.             cursor = frommark;
  330.         }
  331.     }
  332. }
  333.  
  334.  
  335. /*ARGSUSED*/
  336. void cmd_append(frommark, tomark, cmd, bang, extra)
  337.     MARK    frommark;
  338.     MARK    tomark;
  339.     CMD    cmd;
  340.     int    bang;
  341.     char    *extra;
  342. {
  343.     long    l;    /* line counter */
  344.  
  345. #ifndef CRUNCH
  346.     /* if '!' then toggle auto-indent */
  347.     if (bang)
  348.     {
  349.         *o_autoindent = !*o_autoindent;
  350.     }
  351. #endif
  352.  
  353.     ChangeText
  354.     {
  355.         /* if we're doing a change, delete the old version */
  356.         if (cmd == CMD_CHANGE)
  357.         {
  358.             /* delete 'em */
  359.             cmd_delete(frommark, tomark, cmd, bang, extra);
  360.         }
  361.  
  362.         /* new lines start at the frommark line, or after it */
  363.         l = markline(frommark);
  364.         if (cmd == CMD_APPEND)
  365.         {
  366.              l++;
  367.         }
  368.  
  369.         /* get lines until no more lines, or "." line, and insert them */
  370.         while (vgets('\0', tmpblk.c, BLKSIZE) >= 0)
  371.         {
  372.             addch('\n');
  373.             if (!strcmp(tmpblk.c, "."))
  374.             {
  375.                 break;
  376.             }
  377.  
  378.             strcat(tmpblk.c, "\n");
  379.             add(MARK_AT_LINE(l), tmpblk.c);
  380.             l++;
  381.         }
  382.     }
  383.  
  384.     /* on the odd chance that we're calling this from vi mode ... */
  385.     redraw(MARK_UNSET, FALSE);
  386. }
  387.  
  388.  
  389. /*ARGSUSED*/
  390. void cmd_put(frommark, tomark, cmd, bang, extra)
  391.     MARK    frommark;
  392.     MARK    tomark;
  393.     CMD    cmd;
  394.     int    bang;
  395.     char    *extra;
  396. {
  397.     /* choose your cut buffer */
  398.     if (*extra == '"')
  399.     {
  400.         extra++;
  401.     }
  402.     if (*extra)
  403.     {
  404.         cutname(*extra);
  405.     }
  406.  
  407.     /* paste it */
  408.     ChangeText
  409.     {
  410.         cursor = paste(frommark, TRUE, FALSE);
  411.     }
  412. }
  413.  
  414.  
  415. /*ARGSUSED*/
  416. void cmd_join(frommark, tomark, cmd, bang, extra)
  417.     MARK    frommark;
  418.     MARK    tomark;
  419.     CMD    cmd;
  420.     int    bang;
  421.     char    *extra;
  422. {
  423.     long    l;
  424.     char    *scan;
  425.     int    len;    /* length of the new line */
  426.  
  427.     /* if only one line is specified, assume the following one joins too */
  428.     if (markline(frommark) == nlines)
  429.     {
  430.         msg("Nothing to join with this line");
  431.         return;
  432.     }
  433.     if (markline(frommark) == markline(tomark))
  434.     {
  435.         tomark += BLKSIZE;
  436.     }
  437.  
  438.     /* get the first line */
  439.     l = markline(frommark);
  440.     strcpy(tmpblk.c, fetchline(l));
  441.     len = strlen(tmpblk.c);
  442.  
  443.     /* build the l